#pragma once

#include "Sock.hpp"
#include <functional>
#include <vector>
#include <unistd.h>
#include <pthread.h>

using func_t = std::function<void(int)>;

class TcpServer;

class ThreadData
{
public:
    ThreadData(int sock, TcpServer* ptr)
        : _sock(sock)
        , _ptr(ptr)
    {}

    ~ThreadData() {}

public:
    int _sock;
    TcpServer* _ptr;
};

class TcpServer
{
public:
    TcpServer(const uint16_t& port, const std::string& ip = "0.0.0.0")
    {
        _listenSock = _sock.Socket();
        _sock.Bind(_listenSock, port, ip);
        _sock.Listen(_listenSock);
    }

    ~TcpServer()
    {
        if(_listenSock >= 0) close(_listenSock);
    }

    void BindService(func_t func)
    {
        _func.push_back(func);
    }

    void Start()
    {
        while(true)
        {
            std::string clientIP;
            uint16_t clientPort;
            int sock = _sock.Accept(_listenSock, &clientIP, &clientPort);
            if(sock == -1) continue;
            logMessage(NORMAL, "Create A New Link! Socket:%d", sock);
            pthread_t tid;
            ThreadData* td = new ThreadData(sock, this);
            pthread_create(&tid, nullptr, ThreadRoutine, (void*)td);
        }
    }

    void ExcuteService(int sock)
    {
        for(auto& f : _func)
        {
            f(sock);
        }
    }

private:
    static void* ThreadRoutine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        td->_ptr->ExcuteService(td->_sock);
        close(td->_sock);
        delete td;
        return nullptr;
    }   

private:
    Sock _sock;
    int _listenSock;
    std::vector<func_t> _func;
    // std::unordered_map<std::string, func_t> _func; 
};